﻿#include "serialmanager.h"
#include <QSerialPortInfo>
#include <qdebug.h>
#include "crc.h"

serialManager::serialManager(QObject* parent) : QObject(parent), pollingActive(false)
{

    port = new QSerialPort;
    subThread = new QThread;
//设置轮询的时间
    pollingTime = new QTimer;
//将串口和本程序移入子线程进行处理
    this->moveToThread(subThread);
    port->moveToThread(subThread);
    pollingTime->moveToThread(subThread);

    //线程启动则开始进行相关的轮询工作
    connect(subThread, &QThread::started, this, &serialManager::startPollDivices);
    connect(pollingTime, &QTimer::timeout, this, &serialManager::pollDivcies);
    subThread->start();

}

serialManager::~serialManager()
{
    stopPollDivcies();
    stopSerialPort();
//线程退出和销毁
    subThread->quit();
    subThread->wait();
    delete port;
    delete subThread;
    delete pollingTime;
}


//设置串口的参数和打开串口
void serialManager::openSerialPort(const portSettings& portSeting)
{
    if(port->isOpen())
    {
        emit sigserialIsOpen("串口已经打开，无需重复打开");
        return;
    }
    port->setFlowControl(QSerialPort::NoFlowControl);
    port->setPortName(portSeting.portName);
    port->setBaudRate(portSeting.boudRate, QSerialPort::AllDirections);
    port->setDataBits(portSeting.dataBits);
    port->setParity(portSeting.parity);
    port->setStopBits(portSeting.stopBoits);
    responseTimeSet = portSeting.responseTime;


    qDebug() << "BaudRate:" << port->portName();
    qDebug() << "BaudRate:" << port->baudRate();
    qDebug() << "DataBits:" << port->dataBits();
    qDebug() << "StopBits:" << port->parity();
    qDebug() << "Parity:" << port->stopBits();
    qDebug() << "ResponseTime:" << responseTimeSet;

    if(!port->open(QIODevice::ReadWrite))
    {
        emit sigerrorOccured("串口打开失败：" + port->errorString());
        return;
    }
    //否则发送串口打开成功的信号
    emit sigserialOpen("串口打开成功");
}


//设置串口的关闭
void serialManager::stopSerialPort()
{
    if(port->isOpen())
    {
        port->close();
        emit sigserialClose("串口已关闭");
    }
}

//唤醒线程继续轮询
void serialManager::startPollDivices()
{
    if(!pollingActive)
    {
        pollingActive = true;
        //在这里设置了轮询的时间
        pollingTime->start(100);
    }
}

//停止轮询
void serialManager::stopPollDivcies()
{
    pollingActive = false;
    pollingTime->stop();
    waitCondition.wakeOne();
}

//发送指令队列
void serialManager::sendCommand2Divice(int deviceID, const QByteArray& commmand)
{
    QMutexLocker locker(&mutex);
    requestQueue.enqueue(qMakePair(deviceID, commmand));
    waitCondition.wakeOne();
}

//设备指令发送
void serialManager::pollDivcies()
{
    QMutexLocker locker(&mutex);
    if(!port->isOpen())
        return;
    //如果指令容器不为空，执行命令
    while(!requestQueue.isEmpty())
    {
        QPair<int, QByteArray> request = requestQueue.dequeue();
        int deviceID = request.first;
        QByteArray command = request.second;

        port->write(command);

        qDebug() << "发送到设备" << deviceID << ": " << command.toHex();

        port->waitForReadyRead(responseTimeSet);;
        // if(port->waitForReadyRead(responseTimeSet))//这里采用if判断始终为假？？？？？
        // {
        QByteArray response;
        response.resize(9);
        response = port->readAll();
        qDebug() << "收到设备" << deviceID << ": " << response.toHex();
        emit sigdataReceive(deviceID, response);
        // }
    }
    //如果轮询指令为真，则执行轮询命令
    if (pollingActive)
    {
        for (int deviceID = 1; deviceID <= 2; deviceID++)
        {
            QByteArray request = creatModbusRequest(deviceID, 0X04, 0X0000, 2);
            requestQueue.enqueue(qMakePair(deviceID, request));
        }
    }
}


//Modbus请求命令生成函数
QByteArray serialManager::creatModbusRequest(int deviceID, uint8_t functionCode,
        uint16_t startAddress, uint16_t registerCount)
{

    unsigned char request[8];

    request[0] = static_cast<unsigned char>(deviceID);          // 设备地址
    request[1] = functionCode;                                  // 功能码 (0x04 = 读取输入寄存器)
    request[2] = static_cast<unsigned char>((startAddress >> 8) & 0xFF); // 起始地址 高字节
    request[3] = static_cast<unsigned char>(startAddress & 0xFF);        // 起始地址 低字节
    request[4] = static_cast<unsigned char>((registerCount >> 8) & 0xFF); // 读取数量 高字节
    request[5] = static_cast<unsigned char>(registerCount & 0xFF);        // 读取数量 低字节

    uint16_t crc = CRC16(request, 6);
    request[6] = static_cast<unsigned char>(crc & 0xFF); // CRC 低字节
    request[7] = static_cast<unsigned char>((crc >> 8) & 0xFF); // CRC 高字节

    return QByteArray(reinterpret_cast<char*>(request), sizeof(request));

}











